/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Hardware.h"
#include "Creator.h"
#include <Gluck.h>
#include <Converter.h>
#include <logs/Log.h>
#include <WindowImpl.h>

#pragma comment(lib,"dxguid.lib")

namespace liba
{
namespace noise
{
namespace hard
{
namespace directx8
{
	
static HINSTANCE dsound_dll = 0;
typedef HRESULT (FAR PASCAL * LPDIRECTSOUNDCREATE8)(GUID*, LPDIRECTSOUND8*, IUnknown FAR*);
static LPDIRECTSOUNDCREATE8 direct_sound_create = 0;
static Hardware * sound_hardware = 0;

Creator::Creator()
{
	HWND wnd = get_window()->get_wnd();
	if( sound_hardware )
		throw Gluck(__FUNCTION__, "Hardware already exists");
	dsound_dll = LoadLibrary("DSOUND.DLL");

	if( !dsound_dll )
	{
		logs::log() << logs::error << "DirectSound is lower than 8\n";
		return;
	}
	direct_sound_create = (LPDIRECTSOUNDCREATE8) GetProcAddress(dsound_dll, "DirectSoundCreate8");
	if( !direct_sound_create )
	{
		logs::log() << logs::error << "DirectSound is lower than 8\n";
		return;
	}

	IDirectSound8 * lpds = 0;
	HRESULT hr = direct_sound_create( 0, &lpds, 0 );
	if( FAILED(hr) )
	{
		logs::log() << logs::error << "Failed to create DirectSound instance\n";
		return;
	}
	hr = lpds->SetCooperativeLevel( wnd, DSSCL_PRIORITY );
	if( FAILED(hr) )
	{
		logs::log() << logs::error << "Failed to SetCooperativeLevel\n";
		return;
	}

	IDirectSoundBuffer * primary_buffer = 0;

    // Get the primary buffer 
    DSBUFFERDESC desc;
    ZeroMemory( &desc, sizeof(DSBUFFERDESC) );
    desc.dwSize        = sizeof(DSBUFFERDESC);
    desc.dwFlags       = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
    desc.dwBufferBytes = 0;
    desc.lpwfxFormat   = 0;

    if( FAILED( hr = lpds->CreateSoundBuffer( &desc, &primary_buffer, 0 ) ) )
	{
		logs::log() << logs::error << "Failed to CreateSoundBuffer\n";
        return;
	}
    WAVEFORMATEX wfx;
    ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
    wfx.wFormatTag      = WAVE_FORMAT_PCM; 
    wfx.nChannels       = 2; 
    wfx.nSamplesPerSec  = 22050; 
    wfx.wBitsPerSample  = 16;
    wfx.nBlockAlign     = (wfx.wBitsPerSample / 8 * wfx.nChannels);
    wfx.nAvgBytesPerSec = (wfx.nSamplesPerSec * wfx.nBlockAlign);

    if( FAILED( hr = primary_buffer->SetFormat(&wfx) ) )
	{
		logs::log() << logs::error << "Failed to primary_buffer->SetFormat\n";
        return;
	}
	sound_hardware = new Hardware(lpds, primary_buffer);
}

Creator::~Creator()
{
	delete sound_hardware; sound_hardware = 0;
	direct_sound_create = 0;
	FreeLibrary( dsound_dll ); dsound_dll = 0;
}

void Creator::life_cycle(double delta_time)
{
	if( sound_hardware )
		sound_hardware->life_cycle( delta_time );
}

} // namespace directx8
} // namespace hard
} // namespace noise
} // namespace liba


